#include "vl_container.h"

using namespace VL;



/**
 * @Author: CimZzz
 * @Date: 2022-08-04 16:07:50
 * 
 * 构造函数
 * 
 * @param filePtr 文件指针
 */
FileWrapper::FileWrapper(VLFile* filePtr): filePtr(filePtr), observerFileList(nullptr), dependentFileList(nullptr), fileKey("") {
	this->modifyTime = -1;
	this->flag = 0;
	this->changeEnum = FileWrapper::FileChangedEnum::None;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 16:07:50
 * 
 * 构造函数
 * 
 * @param filePtr 文件指针
 */
FileWrapper::FileWrapper(std::shared_ptr<VLFile> filePtr): filePtr(filePtr), observerFileList(nullptr), dependentFileList(nullptr) {
	this->modifyTime = -1;
	this->flag = 0;
	this->changeEnum = FileWrapper::FileChangedEnum::None;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 16:10:15
 * 
 * 获取文件指针
 * 
 * @return 文件指针
 */
std::shared_ptr<VLFile> FileWrapper::getFilePtr() const {
	return this->filePtr;
}


/**
 * @Author: CimZzz
 * @Date: 2022-08-04 23:38:13
 * 
 * 获取文件的绝对路径
 * 
 * @return 文件绝对路径
 */
std::string FileWrapper::getAbsolutePath() const {
	return this->filePtr->getAbsolutePath();
}


/**
 * @Author: CimZzz
 * @Date: 2022-08-04 16:14:35
 * 
 * 获取文件最新修改时间
 * 
 * @return 文件最新修改时间
 */
int64_t FileWrapper::getModifyTime() {
	if(this->modifyTime != -1) {
		return this->modifyTime;
	}

	this->modifyTime = this->filePtr->getModifyTime();

	return this->modifyTime;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 19:29:10
 * 
 * 更新文件修改时间
 * 
 * @return 返回更新后的修改时间
 */
int64_t FileWrapper::updateModifyTime() {
	this->modifyTime = this->filePtr->getModifyTime();

	return this->modifyTime;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 16:17:23
 * 
 * 获取文件变化枚举
 * 
 * @return 文件变化枚举
 */
FileWrapper::FileChangedEnum FileWrapper::getFileChangeEnum() const {
	return this->changeEnum;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 12:25:52
 * 
 * 判断文件是否发生变化
 * 
 * @return 如果文件发生变化返回 ture
 */
bool FileWrapper::isFileChange() {
	return this->changeEnum == FileWrapper::FileChangedEnum::Changed;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 23:59:15
 * 
 * 获取文件键值
 */
std::string FileWrapper::getFileKey() const {
	return this->fileKey;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:44:19
 * 
 * 获取文件标志
 * 
 * @return 文件标志
 */
uint32_t FileWrapper::getFileFlag() const {
	return this->flag;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:44:49
 * 
 * 判断文件是否包含某个标志
 * 
 * @param flag 检查的文件标志
 * 
 * @return 如果存在返回 true
 */
bool FileWrapper::containFlag(uint32_t flag) const {
	return (this->flag & flag) != 0;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 16:52:19
 * 
 * 获取依赖文件列表
 * 
 * @return 依赖文件列表指针
 */
std::shared_ptr<std::vector<std::shared_ptr<FileWrapper>>> FileWrapper::getDependentFileList() const {
	return this->dependentFileList;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 12:32:33
 * 
 * 获取首位依赖文件
 * 
 * @return 首位依赖文件
 */
std::shared_ptr<FileWrapper> FileWrapper::getFirstDependentFile() {
	if(this->dependentFileList.get() == nullptr || this->dependentFileList->empty()) {
		return std::shared_ptr<FileWrapper>(nullptr);
	}

	return this->dependentFileList->at(0);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-12 14:14:32
 * 
 * 获取校验文件
 * 
 * @return 校验文件指针
 */
std::shared_ptr<ValidFile> FileWrapper::getValidFilePtr() {
	return this->validFilePtr;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-09 14:51:57
 * 
 * 将所有依赖文件路径组合成一个字符串
 * @param buffer 字节缓冲区
 * @param wrapPrefix 路径前缀
 * @param wrapPostfix 路径后缀
 * @param separator 分隔符
 * 
 * @note 组装好的字符串会输出到字节缓冲区中
 */
void FileWrapper::composeDependentFiles(Buffer* buffer, const char * wrapPrefix, const char * wrapPostfix, const char * separator) {
	if(this->dependentFileList.get() == nullptr || this->dependentFileList->empty()) {
		return;
	}

	bool isFirst = true;
	for(auto iter = this->dependentFileList->begin() ; iter != this->dependentFileList->end() ; iter ++) {
		if(isFirst) {
			isFirst = false;
		} else {
			if(separator != nullptr) {
				buffer->appendStrBuffer(separator);
			}
		}
		
		if(wrapPrefix != nullptr) {
			buffer->appendStrBuffer(wrapPrefix);
		}

		buffer->appendStrBuffer((*iter)->getAbsolutePath());
		
		if(wrapPostfix != nullptr) {
			buffer->appendStrBuffer(wrapPostfix);
		}
	}

	return;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 16:21:50
 * 
 * 设置文件是否发生变化
 * 
 * @param isChanged 如果文件发生变化传 true
 * @param changeHook 触发观察者变化事件回调, 第一个参数是发生变化文件指针, 第二个参数是受影响文件的指针, 如果返回值为 true 的话, 在受影响文件处理变化时也会带入 changeHook 方法
 */
void FileWrapper::setFileChanged(bool isChanged, std::function<bool(FileWrapper*, FileWrapper*)> changeHook) {
	if(this->changeEnum == FileWrapper::FileChangedEnum::NotChanged || (isChanged && this->changeEnum == FileWrapper::FileChangedEnum::Changed)) {
		return;
	}

	this->mutex.lock();

	if(this->changeEnum == FileWrapper::FileChangedEnum::NotChanged || (isChanged && this->changeEnum == FileWrapper::FileChangedEnum::Changed)) {
		this->mutex.unlock();
		return;
	}

	this->changeEnum = isChanged ? FileWrapper::FileChangedEnum::Changed : FileWrapper::FileChangedEnum::NotChanged;

	this->mutex.unlock();

	if(isChanged && observerFileList.get() != nullptr) {
		// 发生变化, 通知全部观察者已过期需要重新编译
		for(auto iter = observerFileList->begin() ; iter != observerFileList->end() ; iter ++) {
			if(changeHook) {
				if(changeHook(this, iter->get())) {
					(*iter)->setFileChanged(true, changeHook);
				} else {
					(*iter)->setFileChanged(true);
				}
			} else {
				(*iter)->setFileChanged(true);
			}
		}
		// 清空列表
		observerFileList.reset();
	} else {
		// 未发生变化, 清空列表
		observerFileList.reset();
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 23:58:45
 * 
 * 设置文件键值
 * 
 * @param fileKey 文件价值
 */
void FileWrapper::setFileKey(const std::string& fileKey) {
	this->fileKey = fileKey;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:39:44
 * 
 * 设置文件标志
 * 
 * @param flag 文件标志
 */
void FileWrapper::setFileFlags(uint32_t flag) {
	this->flag = flag;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:40:18
 * 
 * 添加文件标志
 * 
 * @param flag 添加的文件标志
 * 
 * @note 与现有标志进行按位或操作
 */
void FileWrapper::addFileFlags(uint32_t flag) {
	this->flag |= flag;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:41:57
 * 
 * 删除文件标志
 * 
 * @param flag 删除文件标志
 * 
 * @note 将参数标志取反, 与现有标志进行按位与操作
 */
void FileWrapper::delFileFlags(uint32_t flag) {
	this->flag = (~flag) & this->flag;
}


/**
 * @Author: CimZzz
 * @Date: 2022-08-04 16:36:10
 * 
 * 增加监控文件
 * 
 * @param fileWrapper 被监控文件
 * 
 * @note 监控文件, 如果被监控文件需要更新, 则推导本文件同样需要改变 
 */
void FileWrapper::monitorFile(std::shared_ptr<FileWrapper> fileWrapper) {
	if(this->changeEnum != FileWrapper::FileChangedEnum::None) {
		// 如果当前文件已明确了是否发生变化, 那么不再对文件进行监控
		return;
	}

	// 先判断被监控文件的状态, 如果被监控文件
	switch (fileWrapper->changeEnum) {
		case FileChangedEnum::None: {
			// 未检测过, 需要加入观察者列表
			fileWrapper->addObserver(this->shared_from_this());
			break;
		}
		case FileChangedEnum::Changed: {
			// 待监控文件已明确发生变化, 直接改变该文件的变化状态
			this->setFileChanged(true);
			break;
		}
		default:
			// 其他状态直接忽略
			break;
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 16:42:30
 * 
 * 添加到观察者列表中
 * 
 * @param observer 观察者
 */
void FileWrapper::addObserver(std::shared_ptr<FileWrapper> observer) {
	if(this->observerFileList.get() == nullptr) {
		// 创建观察者列表
		this->observerFileList = std::shared_ptr<std::vector<std::shared_ptr<FileWrapper>>>(new std::vector<std::shared_ptr<FileWrapper>>());
	}
	this->observerFileList->push_back(observer);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 16:49:11
 * 
 * 添加依赖文件
 * 
 * @param fileWrapper 依赖文件
 * 
 * @note 依赖文件可以看做是本文件的组成部分, 会自动添加到监控文件列表中
 */
void FileWrapper::addDependentFile(std::shared_ptr<FileWrapper> fileWrapper) {
	if(this->dependentFileList.get() == nullptr) {
		// 创建观察者列表
		this->dependentFileList = std::shared_ptr<std::vector<std::shared_ptr<FileWrapper>>>(new std::vector<std::shared_ptr<FileWrapper>>());
	}

	this->dependentFileList->push_back(fileWrapper);
	this->monitorFile(fileWrapper);
}


/**
 * @Author: CimZzz
 * @Date: 2022-08-12 14:15:02
 * 
 * 安装校验文件
 * 
 * @param validFile 校验文件
 */
void FileWrapper::setupValidFile(ValidFile* validFile) {
	this->validFilePtr = std::shared_ptr<ValidFile>(validFile);
}


/**
 * +======================================================================================================================+
 * @Author: CimZzz
 * @Date: 2022-08-04 17:06:28
 * 
 * 代码分割块，以下内容涉及: 
 * 
 * File Pool
 * 
 */

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 17:00:26
 * 
 * 构造函数
 */
FilePool::FilePool() {

}

/**
 * @Author: CimZzz
 * @Date: 2022-07-29 18:41:44
 * 
 * 获取文件
 * 
 * @param sourceKey 文件键值
 * @param callback 如果文件不存在, 则会调用此回调来生成文件实例
 * @param absolutePathAsKey 文件全路径额外作为键值
 * 
 * @return 文件
 */
std::shared_ptr<FileWrapper> FilePool::fetchFile(const std::string& sourceKey, FetchCallback callback, bool absolutePathAsKey) {
	auto iter = this->fileMap.find(sourceKey);
	if(iter == this->fileMap.end()) {
		// 不存在该源文件
		if(callback) {
			std::shared_ptr<FileWrapper> filePtr = callback();
			if(filePtr.get() == nullptr) {
				return filePtr;
			}
			filePtr->setFileKey(sourceKey);
			this->fileMap.emplace(sourceKey, filePtr);
			if(absolutePathAsKey) {
				// Source Key 发生变化
				this->fileMap.emplace(filePtr->getFilePtr()->getAbsolutePath(), filePtr);
			}
			this->fileList.push_back(filePtr);
			return filePtr;
		}
		return std::shared_ptr<FileWrapper>(nullptr);
	} 
	
	return iter->second;
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-29 18:41:44
 * 
 * 获取文件, 同步控制
 * 
 * @param sourceKey 文件键值
 * @param callback 如果文件不存在, 则会调用此回调来生成文件实例
 * @param absolutePathAsKey 文件全路径额外作为键值
 * 
 * @return 文件
 */
std::shared_ptr<FileWrapper> FilePool::fetchFileSync(const std::string& sourceKey, FetchCallback callback, bool absolutePathAsKey) {
	std::lock_guard<std::mutex> locker(this->mutex);
	return this->fetchFile(sourceKey, callback, absolutePathAsKey);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 22:32:21
 * 
 * 获取文件列表指针
 * 
 * @return 文件列表指针
 */
std::vector<std::shared_ptr<FileWrapper>>* FilePool::getFileList() {
	return &this->fileList;
}

/**
 * +======================================================================================================================+
 * @Author: CimZzz
 * @Date: 2022-08-05 14:25:58
 * 
 * 代码分割块，以下内容涉及: 
 * 
 * File Collector
 * 
 */


/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:14:08
 * 
 * 构造函数
 */
FileCollector::FileCollector() {

}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:23:03
 * 
 * 保存主要文件
 * 
 * @param key 文件键值
 * @param filePtr 主要文件指针
 */
void FileCollector::savePrimaryFile(const std::string& key, const std::shared_ptr<FileWrapper>& filePtr) {
	std::shared_ptr<FileWrapper> otherPtr(nullptr);
	this->saveFile(key, filePtr, otherPtr);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:24:19
 * 
 * 保存关联文件
 * 
 * @param key 文件键值
 * @param filePtr 关联文件指针
 */
void FileCollector::saveRelateFile(const std::string& key, const std::shared_ptr<FileWrapper>& filePtr) {
	std::shared_ptr<FileWrapper> otherPtr(nullptr);
	this->saveFile(key, otherPtr, filePtr);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:25:00
 * 
 * 保存文件
 * 
 * @param key 文件键值
 * @param primaryFile 主要文件指针
 * @param relateFile 关联文件指针
 */
void FileCollector::saveFile(const std::string& key, const std::shared_ptr<FileWrapper>& primaryFile, const std::shared_ptr<FileWrapper>& relateFile) {
	std::lock_guard<std::mutex> locker(this->mutex);
	auto iter = this->fileMap.find(key);
	std::shared_ptr<FileCollectorPair> pairPtr;
	if(iter != this->fileMap.end()) {
		// 找到对象
		pairPtr = iter->second;
	} else {
		pairPtr = std::shared_ptr<FileCollectorPair>(new FileCollectorPair());
		this->fileMap.emplace(key, pairPtr);
	}

	if(pairPtr->primaryFile.get() == nullptr && primaryFile.get() != nullptr) {
		pairPtr->primaryFile = primaryFile;
	}

	if(relateFile.get() != nullptr) {
		if(pairPtr->relateFile.get() == nullptr) {
			pairPtr->relateFile = std::shared_ptr<std::vector<std::shared_ptr<FileWrapper>>>(new std::vector<std::shared_ptr<FileWrapper>>);
		}
		pairPtr->relateFile->push_back(relateFile);
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 16:16:03
 * 
 * 判断当前文件搜集器是否为空
 * 
 * @return 如果为空返回 true
 */
bool FileCollector::empty() const {
	return this->fileMap.empty();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 16:17:03
 * 
 * 返回当前文件搜集器数据尺寸
 * 
 * @return 文件搜集器数据尺寸
 */
uint32_t FileCollector::getSize() const {
	return this->fileMap.size();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:29:37
 * 
 * 获取文件搜集器 Map 的起始迭代器
 * 
 * @return Map 的终止迭代器
 */
std::unordered_map<std::string, std::shared_ptr<FileCollectorPair>>::iterator FileCollector::begin() {
	return this->fileMap.begin();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 14:29:37
 * 
 * 获取文件搜集器 Map 的终止迭代器
 * 
 * @return Map 的终止迭代器
 */
std::unordered_map<std::string, std::shared_ptr<FileCollectorPair>>::iterator FileCollector::end() {
	return this->fileMap.end();
}

/**
 * +======================================================================================================================+
 * @Author: CimZzz
 * @Date: 2022-08-22 08:54:34
 * 
 * 代码分割块，以下内容涉及: 
 * 
 * FileWrapperWalker
 * 
 */

/**
 * @Author: CimZzz
 * @Date: 2022-08-22 08:48:19
 * 
 * 构造函数
 * 
 * @param fileWrapperListPtr 文件列表指针
 */
FileWrapperWalker::FileWrapperWalker(std::vector<std::shared_ptr<FileWrapper>>* fileWrapperListPtr): fileWrapperListPtr(fileWrapperListPtr) {

}

/**
 * @Author: CimZzz
 * @Date: 2022-08-22 08:50:54
 * 
 * 确保文件分组存在
 * 
 * @param count 分组数
 */
void FileWrapperWalker::makeSureGroupExist(int count) {
	if(this->fileGroup.size() >= count) {
		return;
	}
	for(int i = 0 ; i < count ; i ++) {
		this->fileGroup.push_back(std::shared_ptr<std::vector<std::shared_ptr<FileWrapper>>>(new std::vector<std::shared_ptr<FileWrapper>>));
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-22 08:51:46
 * 
 * 获取文件列表指针
 * 
 * @return 文件列表指针
 */
const std::vector<std::shared_ptr<FileWrapper>>* FileWrapperWalker::getFileListPtr() const {
	return this->fileWrapperListPtr;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-22 13:36:22
 * 
 * 获取文件组数量
 * 
 * @return 文件组数量
 */
unsigned int FileWrapperWalker::getGroupCount() const {
	return this->fileGroup.size();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-22 08:53:56
 * 
 * 获取文件组指针
 * 
 * @param groupIdx 组下标
 * 
 * @return 文件组指针
 */
std::shared_ptr<std::vector<std::shared_ptr<FileWrapper>>> FileWrapperWalker::getGroupPtr(unsigned int groupIdx) {
	return this->fileGroup.at(groupIdx);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-22 08:52:39
 * 
 * 将文件保存至指定组
 * 
 * @param groupIdx 组下标
 * @param filePtr 文件指针
 */
void FileWrapperWalker::saveFileAt(unsigned int groupIdx, const std::shared_ptr<FileWrapper>& filePtr) {
	this->fileGroup.at(groupIdx)->push_back(filePtr);
}